package org.utils.ui.xml;

import java.util.Collections;
import java.util.Enumeration;

import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;

import org.utils.xml.XMLDataNode;

/**
 * @author Manuel EVENO
 */
public class XMLDataTreeNode extends XMLDataNode implements MutableTreeNode
{
	protected static final String CLOSING_ANGLE_AND_TAG = " />";

	public static final int TAG = 0;
	public static final int ATTRIBUTE = 1;

	protected int type = TAG;
	protected Object userObject;
	/**
	 * Constructor for XMLDataTreeNode.
	 * @param pName
	 */
	public XMLDataTreeNode(String pName)
	{
		this(pName, null);
	}
	/**
	 * Constructor for XMLDataTreeNode.
	 * @param pName
	 * @param pNodeFather
	 */
	public XMLDataTreeNode(String pName, XMLDataNode pNodeFather)
	{
		super(pName, pNodeFather);
		setUserObject(pName);
	}
	/**
	 * Sets the type of the node
	 * @param pType Must be one of TAG or ATTRIBUTE
	 */
	public void setType(int pType)
	{
		type = pType;
	}
	/**
	 * Returns the type of the node, which must be one of TAG or ATTRIBUTE
	 * @return int
	 */
	public int getType()
	{
		return type;
	}
	/** Add an attribute to the node */
	public void addAttribute(String pKey, String pValue)
	{
		super.addAttribute(pKey, pValue);
		XMLDataTreeNode node = new XMLDataTreeNode(pKey, this);
		node.setValue(pValue);
		node.setType(ATTRIBUTE);
		mChildren.add(0, node);
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#insert(MutableTreeNode, int)
	 */
	public void insert(MutableTreeNode child, int index)
	{
		mChildren.add(index, child);
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#remove(int)
	 */
	public void remove(int index)
	{
		mChildren.remove(index);
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#remove(MutableTreeNode)
	 */
	public void remove(MutableTreeNode node)
	{
		mChildren.remove(node);
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#setUserObject(Object)
	 */
	public void setUserObject(Object object)
	{
		userObject = object;
	}
	/**
	 * Returns the userObject.
	 * @return Object
	 */
	public Object getUserObject()
	{
		return userObject;
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#removeFromParent()
	 */
	public void removeFromParent()
	{
		setFather(null);
	}
	/**
	 * @see javax.swing.tree.MutableTreeNode#setParent(MutableTreeNode)
	 */
	public void setParent(MutableTreeNode newParent)
	{
		setFather((XMLDataNode) newParent);
	}
	/**
	 * @see javax.swing.tree.TreeNode#getChildAt(int)
	 */
	public TreeNode getChildAt(int childIndex)
	{
		return (TreeNode) mChildren.get(childIndex);
	}
	/**
	 * @see javax.swing.tree.TreeNode#getChildCount()
	 */
	public int getChildCount()
	{
		return mChildren.size();
	}
	/**
	 * Returns if the node has real child (not counting the attributes set as tags)
	 */
	public boolean hasChildren()
	{
		if (getChildCount() == 0)
			return false;
		for (int i = 0; i < mChildren.size(); i++)
		{
			XMLDataTreeNode child = (XMLDataTreeNode) mChildren.get(i);
			if (child.getType() == TAG)
				return true;
		}
		return false;
	}
	/**
	 * @see javax.swing.tree.TreeNode#getParent()
	 */
	public TreeNode getParent()
	{
		return (TreeNode) getFather();
	}
	/**
	 * @see javax.swing.tree.TreeNode#getIndex(TreeNode)
	 */
	public int getIndex(TreeNode node)
	{
//		if (! mChildren.contains(node))
//			return -1;
		for (int i = 0; i < mChildren.size(); i++)
		{
			if (mChildren.get(i) == node)
				return i;			
		}
		return -1;
	}
	/**
	 * @see javax.swing.tree.TreeNode#getAllowsChildren()
	 */
	public boolean getAllowsChildren()
	{
		return true;
	}
	/**
	 * @see javax.swing.tree.TreeNode#isLeaf()
	 */
	public boolean isLeaf()
	{
		return (getChildCount() == 0);
	}
	/**
	 * @see javax.swing.tree.TreeNode#children()
	 */
	public Enumeration children()
	{
		return Collections.enumeration(mChildren);
	}
	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString()
	{
		String str = getUserObject().toString();
		if (getType() == TAG)
			str = "<"+str+">";
		return str;
	}
	/**
	 * @see org.utils.xml.XMLDataNode#getName()
	 */
	public String getName()
	{
		return super.getName();
	}
	/**
	 * @see org.utils.xml.XMLDataNode#getValue()
	 */
	public String getValue()
	{
		return super.getValue();
	}
	/**
	 * @see org.utils.xml.XMLDataNode#setName(java.lang.String)
	 */
	public void setName(String pNewName)
	{
		super.setName(pNewName);
	}
	/**
	 * @see org.utils.xml.XMLDataNode#setValue(java.lang.String)
	 */
	public void setValue(String pValue)
	{
		super.setValue(pValue);
/*		if (getType() == ATTRIBUTE)
		{
			((XMLDataTreeNode) getParent()).setAttribute(getName(), pValue);
		}*/
	}
   /**
    * Generate an XML String with the content of the tree.<br>
    * Here is a sample code:<p>
    * <code>
    * StringBuffer xmlResult = new StringBuffer(200);<br>
    * resultNode = new XMLDataNode(mBusinessClass, null);<br>
    * ... <br>
    * resultNode.toXMLString(xmlResult);<br>
    * </code><p>
    */
    public void toXMLString( StringBuffer xmlBuffer ) {
	if( xmlBuffer == null )
	    throw new java.lang.NullPointerException();

	addIndentationSpaces( xmlBuffer, depth() * indentationLevel );

	openElement( xmlBuffer, mName );

	// Process attributes
	if ( mAttributes.size() == NO_ATTRIBUTES ) {
	    // no attibutes
	    closeOpenedElement( xmlBuffer );
	}
/*	else if ( ( mAttributes.size() == 1 ) && ( mAttributes.get( "value" ) != null ) ) {
	    // one attribute named 'value'
	    //    will produce : <attributeName> attributeValue </attributeName>
	    closeOpenedElement( xmlBuffer );
	    xmlBuffer.append( SPACE );
	    xmlBuffer.append( mAttributes.get( "value" ) );
	}*/
	else {
	    // several attributes
	    for( int i = 0; i < mChildren.size(); i++ )
	    {
	    	XMLDataTreeNode child = (XMLDataTreeNode) mChildren.get(i);
	    	if (child.getType() == ATTRIBUTE)
		{
			xmlBuffer.append( SPACE );
			xmlBuffer.append( child.getUserObject() + "=\"" + child.getValue() +"\"" );
		}
	    }
/*	    Iterator itAttributes = mAttributes.keySet().iterator();
	    while( itAttributes.hasNext() ) {
		String attributeName = ( String )itAttributes.next();
		xmlBuffer.append( SPACE );
		xmlBuffer.append( attributeName + "=\"" + ( String )mAttributes.get( attributeName ) +"\"" );
	    }*/
	    closeOpenedElement( xmlBuffer );
	}

	if (mChildren.size() == 0 )
	{
	    xmlBuffer.append( SPACE );
	}
	else if (hasChildren())
	{
	    // process children
	    xmlBuffer.append( NEWLINE );
	    for( int i = 0; i < mChildren.size(); i++ )
	    {
	    	XMLDataTreeNode child = (XMLDataTreeNode) mChildren.get(i);
	    	if (child.getType() != ATTRIBUTE)
			child.toXMLString( xmlBuffer );
	    }
	    addIndentationSpaces( xmlBuffer, depth() * indentationLevel );
	}

	// append "closing" element
	closeElement( xmlBuffer, mName );
	xmlBuffer.append( NEWLINE );
    }

    protected void closeOpenedElement( StringBuffer buf )
    {
	if (hasChildren())
		buf.append( CLOSING_ANGLE );
	else
		buf.append( CLOSING_ANGLE_AND_TAG );
    }

    protected void closeElement( StringBuffer buf, String elementName )
    {
    	if (! hasChildren())
    		return ;
	buf.append( OPENING_ANGLE_END_TAG );
	buf.append( elementName );
	buf.append( CLOSING_ANGLE );
    }
}
